/**
 * 网关地址
 * @type {string}
 */

// 网关地址
const GATEWAY_ADDRESS = 'http://localhost:9999';

/**
 * UPMS模块
 * @type {string}
 */
const UPMS_ADDRESS = GATEWAY_ADDRESS + '/' + 'upms';


/**
 * token名称
 * @type {string}
 */
const TOKEN_NAME = 'satoken';

/**
 * url白名单
 * @type {string[]}
 */
const WHITE_LIST = [];

/**
 * 路由守卫
 */
function routeGuard() {
    // 获取当前页面的url相对路径
    let pathName = window.location.pathname;
    // 获取token
    let token = getCookie(TOKEN_NAME);
    if (!token) {
        // 白名单直接放行
        if (WHITE_LIST.indexOf(pathName) !== -1) {
            return;
        }
        location.href = '/views/login.html';
        return;
    }
    if (pathName === '/') {
        location.href = '/views/index.html';
    }
}

/**
 * 为jQuery ajax设置默认请求头
 */
(function ajaxSetup() {
    let $ = layui.$;
    let tokenValue = getCookie(TOKEN_NAME);
    let headers = {};
    headers[TOKEN_NAME] = tokenValue;
    // 页面跳转会携带cookie tenantId
    if (getCookie('tenantId')) {
        setItemLocalStorage('tenantId', Number(getCookie('tenantId')));
    }
    // 页面跳转会携带cookie userId
    if (getCookie('userId')) {
        setItemLocalStorage('userId', Number(getCookie('userId')));
    }
    headers['tenantId'] = getItemLocalStorage('tenantId');
    headers['userId'] = getItemLocalStorage('userId');
    $.ajaxSetup(
        {
            headers: headers,
            beforeSend: xhr => {
                routeGuard();
            },
            error: (xhr, status, error) => {
                // token无效时，返回登录页
                if (error === 'Forbidden' || error === 'Unauthorized') {
                    location.href = '/views/login.html';
                }
            }
        }
    );
})();

// *******************************************************通用自定义封装方法Start************************************************************** //

/**
 * 发起网络请求
 * @param url           请求地址
 * @param data          请求参数
 * @param method        请求方法
 * @param contentType   内容类型
 * @param header        请求头
 * @param showLoading   是否显示loading
 * @param async         是否异步
 * @param beforeSendFn  发送之前的方法
 * @param completeFn    完成发送的方法
 * @returns {Promise<unknown>}
 */
function request(url, data = {}, method = "POST", contentType = "application/x-www-form-urlencoded", header = {}, showLoading = true, async = true, beforeSendFn, completeFn) {
    // 显示loading
    let loading;
    if (showLoading) {
        loading = layer.load();
    }
    // 合并请求头
    const mergedHeader = Object.assign(header, {});
    return new Promise((resolve, reject) => {
        layui.$.ajax({
            url: url,
            data: data,
            header: mergedHeader,
            method: method,
            timeout: 300000,
            contentType: contentType,
            async: async,
            success: (result, status, xhr) => {
                if (result.code === 200) {
                    resolve(result);
                } else {
                    reject(result.msg);
                }
            },
            error: (xhr, status, error) => {
                let responseJSON = xhr.responseJSON;
                layer.msg(responseJSON.msg);
                reject(responseJSON);
            },
            beforeSend: beforeSendFn ? beforeSendFn() : (xhr) => {
            },
            complete: completeFn ? completeFn() : (xhr, status) => {
                layer.close(loading);
            },
        });
    });
}

/**
 * 发起get请求
 * @param url           请求地址
 * @param data          请求参数
 * @param header        请求头
 * @returns {Promise<unknown>}
 */
function getRequest(url, data = {}, header = {}) {
    return request(url, data, "GET", "", header, true);
}

/**
 * 发起post请求（application/x-www-form-urlencoded）
 * @param url           请求地址
 * @param data          请求参数
 * @param header        请求头
 * @returns {Promise<unknown>}
 */
function postForm(url, data = {}, header = {}) {
    return request(url, data, "POST", "application/x-www-form-urlencoded", header, true);
}

/**
 * 发起post请求（application/json;charset=UTF-8）
 * @param url           请求地址
 * @param data          请求参数
 * @param header        请求头
 * @returns {Promise<unknown>}
 */
function postBody(url, data = {}, header = {}) {
    return request(url, data, "POST", "application/json;charset=UTF-8", header, true);
}

/**
 * 判断数组是否包含某元素，不适用于json数组
 * @param    value        某元素
 * @returns  {number}     某元素的下标，若不存在返回-1
 */
Array.prototype.indexOf = function (value) {
    for (let i = 0; i < this.length; i++) {
        if (this[i] === value) {
            return i;
        }
    }
    return -1;
};

/**
 * 判断json数组是否包含某json对象
 * @param   value         某json对象
 * @returns {number}      某元素的下标，若不存在返回-1
 */
Array.prototype.indexOfJson = function (value) {
    return this.findIndex(v => {
        return JSON.stringify(v) === JSON.stringify(value);
    });
};

/**
 * 删除数组中的某元素，不适用于json数组
 * splice改变原数组,slice不改变原数组
 * @param value 某元素
 */
Array.prototype.remove = function (value) {
    let index = this.indexOf(value);
    if (index > -1) {
        this.splice(index, 1);
    }
};
/**
 * 删除json数组中的某json对象
 * splice改变原数组,slice不改变原数组
 * @param value     某json对象
 */
Array.prototype.removeJson = function (value) {
    let index = this.indexOfJson(value);
    if (index > -1) {
        this.splice(index, 1);
    }
};

/**
 * 用text2替换text1
 * @param text1   被替换的字符串
 * @param text2   替换的字符串
 * @returns {*}
 */
String.prototype.replaceAll = function (text1, text2) {
    return this.replace(new RegExp(text1, "g"), text2);
}

/**
 * 获取json对象的key，以数组的方式返回
 * @param json
 * @returns {*[]}
 */
function getKeysFromJson(json) {
    let keys = [];
    for (let key in json) {
        keys.push(key);
    }
    return keys
}

/**
 * 接收上一页面传来的一个值
 * @returns {string}    上一页面传来的一个值
 */
function oneValue() {
    let result;
    // 获取url中"?"符后的字串
    let url = decodeURIComponent(window.location.search);
    if (url.indexOf("?") !== -1) {
        result = url.substr(url.indexOf("=") + 1);
    }
    return result;
}

/**
 * 接收上一页面传来的多个值
 * @returns {{}}    上一页面传来的一组值,以json格式返回
 */
function manyValues() {
    let url = decodeURIComponent(window.location.search);
    let result = {};
    if (url.indexOf("?") !== -1) {
        let str = url.substr(1);
        let params = str.split("&");
        let keys = new Array(params.length);
        let values = new Array(params.length);
        for (let i = 0; i < params.length; i++) {
            keys[i] = params[i].split("=")[0]
            values[i] = decodeURIComponent(params[i].split("=")[1]);
            result[keys[i]] = values[i]
        }
    }
    return result;
}

/**
 * 将url参数字符串解析为JSON对象
 * eg：输入apple=1&banana=2
 *     输出 { apple: "1", banana: "2" }
 * @param queryString url参数字符串()
 * @returns {{}}
 */
function urlParamsToJson(str) {
    const searchParams = new URLSearchParams(str);
    const json = {};
    for (const [key, value] of searchParams.entries()) {
        json[key] = value;
    }
    return json;
}

/**
 * 格式化日期时间
 * @param fmt   显示格式
 * @param date  date对象
 * @returns {*} 格式化后的日期时间
 */
function dateFtt(fmt, date) {
    let o = {
        "y+": date.getMonth(),//年
        "M+": date.getMonth() + 1,//月
        "d+": date.getDate(), //日
        "H+": date.getHours(),//时
        "m+": date.getMinutes(),//分
        "s+": date.getSeconds(),//秒
        "q+": Math.floor((date.getMonth() + 3) / 3),//季
        "S": date.getMilliseconds()//毫秒
    };
    if (/(y+)/.test(fmt))
        fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
    for (let k in o)
        if (new RegExp("(" + k + ")").test(fmt))
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
    return fmt;
}

/**
 * 判断字符串是否为空
 * @param   str         字符串
 * @returns {boolean}
 */
function isEmpty(str) {
    return str === '' || str === 'undefined' || str === 'null' || str === undefined || str === null;
}

/**
 * 判断字符串是否非空
 * @param   str         字符串
 * @returns {boolean}
 */
function isNotEmpty(str) {
    return !isEmpty(str);
}

/**
 * 判断输入的是否为数字
 * @param   value       值
 * @returns {boolean}
 */
function isNumber(value) {
    let pattern1 = /-?[1-9]\d*/;
    let pattern2 = /-?([1-9]\d*.\d*|0.\d*[1-9]\d*)/;
    return pattern1.test(value) || pattern2.test(value);
}

/**
 * 判断终端是否为PC
 * @returns {boolean}
 */
function isPC() {
    let userAgent = navigator.userAgent;
    let Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
    let flag = true;
    for (let v = 0; v < Agents.length; v++) {
        if (userAgent.indexOf(Agents[v]) > 0) {
            flag = false;
            break;
        }
    }
    return flag;
}

/**
 * 获取操作系统信息
 * @returns {string}
 */
function getOS() {
    let sUserAgent = navigator.userAgent;
    let isWin = (navigator.platform === "Win32") || (navigator.platform === "Windows");
    let isMac = (navigator.platform === "Mac68K") || (navigator.platform === "MacPPC") || (navigator.platform === "Macintosh") || (navigator.platform === "MacIntel");
    if (isMac) return "Mac";
    let isUnix = (navigator.platform === "X11") && !isWin && !isMac;
    if (isUnix) return "Unix";
    let isLinux = (String(navigator.platform).indexOf("Linux") > -1);
    if (isLinux) return "Linux";
    if (isWin) {
        let isWin2K = sUserAgent.indexOf("Windows NT 5.0") > -1 || sUserAgent.indexOf("Windows 2000") > -1;
        if (isWin2K) return "Win2000";
        let isWinXP = sUserAgent.indexOf("Windows NT 5.1") > -1 || sUserAgent.indexOf("Windows XP") > -1;
        if (isWinXP) return "WinXP";
        let isWin2003 = sUserAgent.indexOf("Windows NT 5.2") > -1 || sUserAgent.indexOf("Windows 2003") > -1;
        if (isWin2003) return "Win2003";
        let isWinVista = sUserAgent.indexOf("Windows NT 6.0") > -1 || sUserAgent.indexOf("Windows Vista") > -1;
        if (isWinVista) return "WinVista";
        let isWin7 = sUserAgent.indexOf("Windows NT 6.1") > -1 || sUserAgent.indexOf("Windows 7") > -1;
        if (isWin7) return "Win7";
        let isWin10 = sUserAgent.indexOf("Windows NT 10") > -1 || sUserAgent.indexOf("Windows 10") > -1;
        if (isWin10) return "Win10";
    }
    return "other";
}

/**
 * 获取浏览器类型
 * @returns {string}
 */
function whatBrowser() {
    let userAgent = navigator.userAgent;
    if (userAgent.indexOf("Opera") > -1) return "Opera"
    if (userAgent.indexOf("Firefox") > -1) return "Firefox";
    if (userAgent.indexOf("Chrome") > -1) return "Chrome";
    if (userAgent.indexOf("Safari") > -1) return "Safari";
    if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera) return "IE";
}

/**
 * 获取网络类型
 * @returns {string}
 */
function getNetworkType() {
    let ua = navigator.userAgent;
    let networkStr = ua.match(/NetType\/\w+/) ? ua.match(/NetType\/\w+/)[0] : 'NetType/other';
    networkStr = networkStr.toLowerCase().replace('nettype/', '');
    let networkType;
    switch (networkStr) {
        case 'wifi':
            networkType = 'wifi';
            break;
        case '4g':
            networkType = '4g';
            break;
        case '3g':
            networkType = '3g';
            break;
        case '3gnet':
            networkType = '3g';
            break;
        case '2g':
            networkType = '2g';
            break;
        default:
            networkType = '有线';
    }
    return networkType
}

/**
 * 生成uuid
 * @returns {string}
 */
function UUID() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
        let r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

/**
 * 获取两组经纬度之间的直线距离（单位：千米）
 * @param lng1          经度1
 * @param lat1          纬度1
 * @param lng2          经度2
 * @param lat2          纬度2
 * @returns {string}
 */
function getDistance(lng1, lat1, lng2, lat2) {
    function Rad(d) {
        return d * Math.PI / 180.0;
    }

    if (!lng1 || !lat1 || !lng2 || !lat2) {
        return '';
    }
    let radLat1 = Rad(lat1);
    let radLat2 = Rad(lat2);
    let a = radLat1 - radLat2;
    let b = Rad(lng1) - Rad(lng2);
    let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
    s = s * 6378.137;
    s = Math.round(s * 10000) / 10000;
    // 保留两位小数
    return s.toFixed(2);
}

/**
 * 防抖（在一定时间内，如果事件被触发多次，只执行最后一次）
 * @param fn    待执行的方法
 * @param delay 延时
 * @returns {(function(): void)|*}
 */
function debounce(fn, delay) {
    let timer;
    return function () {
        const context = this;
        // 每次触发事件时都会清除之前的定时器
        if (timer) {
            clearTimeout(timer);
        }
        // 重新设置一个新的定时器
        timer = setTimeout(() => {
            fn.call(context);
        }, delay);
    }
}

/**
 * 节流（在一定时间内，如果事件被触发多次，只执行第一次）
 * @param fn    待执行的方法
 * @param delay 延时
 * @returns {(function(): void)|*}
 */
function throttle(fn, delay) {
    let timer;
    return function () {
        const context = this;
        if (!timer) {
            timer = setTimeout(() => {
                fn.call(context);
                timer = null;
            }, delay);
        }
    };
}

/**
 * 设置key,把对象转成json字符串并存入localStorage
 * localStorage值只接受字符串，故用JSON.stringify
 * @param key   键
 * @param val   值
 */
function setItemLocalStorage(key, val) {
    window.localStorage.setItem(key, JSON.stringify(val));
};

/**
 * 获取localStorage中key的值
 * @param   key     键
 * @returns {any}   值
 */
function getItemLocalStorage(key) {
    return JSON.parse(window.localStorage.getItem(key));
}

/**
 * 删除localStorage中的key
 * @param key       键
 */
function removeItemLocalStorage(key) {
    window.localStorage.removeItem(key);
}

/**
 * 清空localStorage
 */
function clearLocalStorage() {
    window.localStorage.clear();
}

/**
 * 设置key,把对象转成json字符串并存入sessionStorage
 * localStorage值只接受字符串，故用JSON.stringify
 * @param key   键
 * @param val   值
 */
function setItemSessionStorage(key, val) {
    window.sessionStorage.setItem(key, JSON.stringify(val));
};

/**
 * 获取sessionStorage中key的值
 * @param   key     键
 * @returns {any}   值
 */
function getItemSessionStorage(key) {
    return JSON.parse(window.sessionStorage.getItem(key));
}

/**
 * 删除sessionStorage中的key
 * @param key       键
 */
function removeItemSessionStorage(key) {
    window.sessionStorage.removeItem(key);
}

/**
 * 清空sessionStorage
 */
function clearSessionStorage() {
    window.sessionStorage.clear();
}

/**
 * 设置cookie
 * @param key
 * @param value
 * @param minutes
 */
function setCookie(key, value, minutes) {
    document.cookie = key + '=' + value + ';expires=' + new Date(new Date().getTime() + minutes * 60 * 1000).toUTCString() + ";path=/";
}

/**
 * 根据key获取cookie
 * @param key
 * @returns {*}
 */
function getCookie(key) {
    let json = {};
    if (document.cookie) {
        let cookies = document.cookie.split('; ');
        for (let i = 0; i < cookies.length; i++) {
            let arr = cookies[i].split('=');
            json[arr[0]] = arr[1];
        }
    }
    return json[key];
}

/**
 * 根据key删除cookie
 * @param key
 */
function removeCookie(key) {
    document.cookie = key + '=0;expires=' + new Date(0).toUTCString() + ";path=/";
}

/**
 * 清空cookie
 */
function clearCookie() {
    let json = {};
    if (document.cookie) {
        let cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            let arr = cookies[i].split('=');
            json[arr[0]] = arr[1];
        }
    }
    for (let key in json) {
        removeCookie(key);
    }
}

/**
 * 初始化websocket
 * @param wsUrl  url
 * @returns {WebSocket}
 */

function initWebsocket(wsUrl) {
    if (typeof (WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
        return null
    }
    let socket = new WebSocket(wsUrl);
    socket.onopen = e => {
        console.log("WebSocket连接成功");
        setInterval(() => socket.send(''), 10 * 1000);
    }
    socket.onerror = e => {
        console.error("WebSocket连接发生错误:", e);
    }
    socket.onclose = e => {
        console.log("WebSocket已关闭，即将重连");
        setTimeout(() => initWebsocket(wsUrl), 3000);
    }
    // 监听窗口关闭事件，当窗口关闭时，客户端主动去关闭websocket连接，防止连接还没断开就关闭窗口，服务端会抛异常
    window.onbeforeunload = () => {
        socket.close();
    }
    return socket
}

// *******************************************************通用自定义封装方法End************************************************************** //

// *******************************************************layui自定义封装方法Start************************************************************** //

layer.config({
    shadeClose: true,
    maxmin: true,
    success: (layero, index) => {
        // 当按下Esc键时，关闭窗口
        layui.$(this).keydown(e => {
            if (e.keyCode === 27) {
                layer.close(index);
            }
        });
    }
});

/**
 * layui--基础操作
 *
 * @param $                jQuery对象
 * @param table            table组件对象
 * @param tableId          table组件的id
 * @param tableFilter      table组件的filter
 * @param searches         顶部所有搜索框的jQuery对象
 * @param del              批量删除接口
 * @param toSaveOrUpdate   新增或更新页面的url
 * @param fun              回调函数
 */
function layuiBase($, table, tableId, tableFilter, searches, del, toSaveOrUpdate, fun) {
    let active = layuiBaseTopBtn($, table, tableId, searches, del, toSaveOrUpdate);
    // 给按钮注册点击事件
    $('.layui-btn').click(function () {
        let type = $(this).data('type');
        active[type] ? active[type].call(this) : '';
    });
    // 当按下回车键时，触发搜索
    searches.keydown(e => {
        if (e.keyCode === 13) {
            $('button[data-type=search]').click();
        }
    });
    // 监听表格行工具栏
    table.on('tool(' + tableFilter + ')', obj => {
        layuiBaseEvent($, table, tableId, searches, del, toSaveOrUpdate, obj);
        fun ? fun(obj) : '';
    });
}

/**
 * layui--基础顶部按钮的实现（基于自定义数据属性data-*）
 * @param $                jQuery对象
 * @param table            table组件对象
 * @param tableId          table组件的id
 * @param searches         顶部所有搜索框的jQuery对象
 * @param del              批量删除接口
 * @param toSaveOrUpdate   新增或更新页面的url
 * @returns {{}}
 */
function layuiBaseTopBtn($, table, tableId, searches, del, toSaveOrUpdate) {
    // 顶部按钮
    return {
        // 搜索
        search: () => {
            // 搜索条件
            let keywords = {};
            searches.each((i, v) => {
                keywords[v.name] = v.value;
            });
            // 重载表格
            table.reload(tableId, {
                where: keywords
            });
        },
        // 清空
        clear: () => {
            searches.each((i, v) => {
                v.value = ''
            });
            // 重载表格
            table.reload(tableId, {
                where: ''
            });
            searches[0].focus();
        },
        // 新增
        save: () => {
            this.layuiOpenFixSizeSubmitWindow('新增', toSaveOrUpdate, '#save', true);
        },
        // 批量删除
        delAll: () => {
            // 得到选中的数据,是一个json数组
            let checkData = table.checkStatus(tableId).data;
            if (checkData.length === 0) {
                return layer.msg('请选择数据');
            }
            let ids = [];
            $.each(checkData, (i, v) => {
                ids.push(v.id);
            });
            this.layuiOpenConfirm('确定删除吗？', () => {
                postForm(del, {ids: ids.toString()}).then(rs => {
                    table.reload(tableId);
                    searches[0].focus();
                });
            });
        },
    }
}

/**
 * layui--基础事件按钮的实现（基于事件lay-event)）
 * @param $                jQuery对象
 * @param table            table组件对象
 * @param tableId          table组件的id
 * @param searches         顶部所有搜索框的jQuery对象
 * @param del              批量删除接口
 * @param toSaveOrUpdate   新增或更新页面的url
 * @param obj              当前行对象
 */
function layuiBaseEvent($, table, tableId, searches, del, toSaveOrUpdate, obj) {
    let data = obj.data;
    // 单个查看
    if (obj.event === 'get') {
        this.layuiOpenFixSizeSubmitWindow('查看', toSaveOrUpdate + data.id, '', true);
    }
    // 单个更新
    if (obj.event === 'update') {
        this.layuiOpenFixSizeSubmitWindow('更新', toSaveOrUpdate + data.id, '#update', true);
    }
    // 单个删除
    if (obj.event === 'del') {
        this.layuiOpenConfirm('真的删除么？', () => {
            postForm(del, {ids: data.id}).then(rs => {
                layer.msg('已删除');
                table.reload(tableId);
                searches[0].focus();
            });
        })
    }
}

/**
 * layui--打开一个新的固定大小的提交窗口
 * @param title     窗口标题
 * @param url       目标url
 * @param filter    后代条件的选择器表达式、元素或 jQuery 对象
 * @param full      是否打开就最大化
 * @returns {*}
 */
function layuiOpenFixSizeSubmitWindow(title, url, filter, full) {
    return this.layuiOpenFloatingSizeSubmitWindow(title, url, '600px', '600px', filter, full);
}

/**
 * layui--打开一个新的非固定大小的提交窗口
 * @param title     窗口标题
 * @param url       目标url
 * @param filter    后代条件的选择器表达式、元素或 jQuery 对象
 * @param width     窗口宽度
 * @param height    窗口高度
 * @param full      是否打开就最大化
 * @returns {*}
 */
function layuiOpenFloatingSizeSubmitWindow(title, url, width, height, filter, full) {
    let index = layer.open({
        type: 2,
        title: title,
        content: url,
        area: [width, height],
        btn: ['确定', '取消'],
        yes: (index, layero) => {
            // 找到iframe里的提交按钮并点击提交
            let submit = layero.find('iframe').contents().find(filter);
            submit.click();
        }
    });
    if (full) {
        layer.full(index);
    }
    return index;
}

/**
 * layui--打开一个新的固定大小的关闭窗口
 * @param title     窗口标题
 * @param url       目标url
 * @param full      是否打开就最大化
 * @returns {*}
 */
function layuiOpenFixSizeCloseWindow(title, url, full) {
    return this.layuiOpenFloatingSizeCloseWindow(title, url, '600px', '600px', full);
}

/**
 * layui--打开一个新的非固定大小的关闭窗口
 * @param title     窗口标题
 * @param url       目标url
 * @param width     窗口宽度
 * @param height    窗口高度
 * @param full      是否打开就最大化
 * @returns {*}
 */
function layuiOpenFloatingSizeCloseWindow(title, url, width, height, full) {
    let index;
    index = layer.open({
        type: 2,
        title: title,
        content: url,
        area: [width, height],
        btn: ['关闭'],
        btn1: (index, layero) => {
            layer.close(index);
        }
    });
    if (full) {
        layer.full(index);
    }
    return index;
}

/**
 * layui--打开一个询问框
 * @param tip 提示信息
 * @param fun 执行方法
 */
function layuiOpenConfirm(tip, fun) {
    layer.confirm(tip ? tip : '是否确定？', {icon: 3, title: '提示'}, index => {
        fun ? fun() : '';
        layer.close(index);
    });
}

/**
 * layui--打开一个图片预览层
 * @param photosData    图片层的数据源
 */
function layuiOpenImagePreview(photosData) {
    layer.photos({
        // 图片层的数据源
        photos: {
            data: photosData
        },
        anim: 5,
        // 点击遮罩层关闭相册
        shadeClose: true,
        // 显示关闭按钮
        closeBtn: 2,
    });
}

/**
 * layui--关闭父页面中的子页面
 */
function layuiCloseChildIframe() {
    // 先得到父页面中当前iframe层的索引
    let index = parent.layer.getFrameIndex(window.name);
    // 再执行关闭
    parent.layer.close(index);
}

/**
 *layui--表单提交--postForm方式
 * @param url       提交的url
 * @param data      提交的数据
 * @param tableId   table组件的id
 * @param fun       回调函数
 */
function layuiSubmit(url, data, tableId, fun) {
    postForm(url, data).then(rs => {
        if (tableId) {
            // 重载表格
            parent.layui.table.reload(tableId);
            // 关闭子页面
            layuiCloseChildIframe();
        }
        fun ? fun(rs) : '';
    });
}

/**
 *layui--表单提交--postBody方式
 * @param url       提交的url
 * @param data      提交的数据
 * @param tableId   table组件的id
 * @param fun       回调函数
 */
function layuiSubmitAsPostBody(url, data, tableId, fun) {
    postBody(url, JSON.stringify(data)).then(rs => {
        if (tableId) {
            // 重载表格
            parent.layui.table.reload(tableId);
            // 关闭子页面
            layuiCloseChildIframe();
        }
        fun ? fun(rs) : '';
    });
}

/**
 * layui上传图片
 * @param $         jQuery
 * @param upload    layui的上传组件
 * @param element   layui的element组件
 * @param btn       上传按钮的jQuery id选择器，如#upload
 * @param url       上传接口
 * @param field     文件域的字段名
 * @param data      接口入参
 * @param multiple  是否允许多文件上传
 * @param progress  进度条组件的lay-filter值
 *
 * @param chooseFun 选择完文件后的回调函数
 * @param doneFun   文件上传完毕的回调函数
 * @param errorMsg  上传请求出现异常的提示消息
 */
function layuiUploadPic($, upload, element, btn, url, field = 'file', data = null, multiple = false, progress = 'progress'
    , chooseFun, doneFun, errorMsg = '上传出错',) {
    // 上传loading
    let load;
    upload.render({
        elem: btn,
        url: url,
        field: 'file',
        data: data,
        multiple: multiple,
        // 选择完文件后的回调
        choose: obj => {
            if (chooseFun) {
                chooseFun(obj);
            }
        },
        // 文件上传前的回调，obj同choose，若返回 false，则表明阻止上传
        before: obj => {
            // 上传loading
            load = layer.load();
            // 进度条复位
            element.progress(progress, 0 + '%');
            layer.msg('上传中', {icon: 16, time: 0});
        },
        // 文件上传完毕的回调
        done: rs => {
            layer.close(load);
            if (doneFun) {
                doneFun(rs);
            }
        },
        // 请求异常的回调
        error: () => {
            layer.close(load);
            layer.msg(errorMsg, {icon: 5});
        },
        // 上传进度的回调
        progress: (n, elem) => {
            element.progress(progress, n + '%');
            if (n === 100) {
                layer.msg('上传完毕', {icon: 1});
            }
        },
        // 选择文件后自动上传
        auto: true,
        // 点了绑定按钮才上传
        // bindAction: '#save',
        // 文件类型
        accept: 'images',
        // 文件名后缀
        exts: 'jpg|png|gif|bmp|jpeg|svg'
    })
}

/**
 * layui上传文件
 * @param $         jQuery
 * @param upload    layui的上传组件
 * @param element   layui的element组件
 * @param btn       上传按钮的jQuery id选择器，如#upload
 * @param url       上传接口
 * @param field     文件域的字段名
 * @param data      接口入参
 * @param multiple  是否允许多文件上传
 * @param progress  进度条组件的lay-filter值
 *
 * @param chooseFun     选择完文件后的回调函数
 * @param doneFun       文件上传完毕的回调函数
 * @param errorMsg      上传请求出现异常的提示消息
 * @param accept        指定允许上传时校验的文件类型
 * @param exts          允许上传的文件后缀。一般结合 accept 属性来设定
 */
function layuiUpload($, upload, element, btn, url, field = 'file', data = null, multiple = false, progress = 'progress'
    , chooseFun, doneFun, errorMsg = '上传出错', accept = 'file', exts = '') {
    // 上传loading
    let load;
    upload.render({
        elem: btn,
        url: url,
        field: 'file',
        data: data,
        multiple: multiple,
        // 选择完文件后的回调
        choose: obj => {
            if (chooseFun) {
                chooseFun(obj);
            }
        },
        // 文件上传前的回调，obj同choose，若返回 false，则表明阻止上传
        before: obj => {
            // 上传loading
            load = layer.load();
            // 进度条复位
            element.progress(progress, 0 + '%');
            layer.msg('上传中', {icon: 16, time: 0});
        },
        // 文件上传完毕的回调
        done: rs => {
            layer.close(load);
            if (doneFun) {
                doneFun(rs);
            }
        },
        // 请求异常的回调
        error: () => {
            layer.close(load);
            layer.msg(errorMsg, {icon: 5});
        },
        // 上传进度的回调
        progress: (n, elem) => {
            element.progress(progress, n + '%');
            if (n === 100) {
                layer.msg('上传完毕', {icon: 1});
            }
        },
        // 选择文件后自动上传
        auto: true,
        // 文件类型
        accept: accept,
        // 文件名后缀
        exts: exts
    })
}

/**
 * layui--基础树形组件
 * @param $                 jQuery对象
 * @param tree              树形组件
 * @param form layui的表单组件
 * @param treeUrl 生成树的url
 * @param checkUrl 返回id数组的url,设置节点勾选
 * @param addUrl 将勾选的节点进行提交的url
 * @param elemTxt 树形组件的jQuery的id选择器文本
 * @param paramId 发送给后端的参数
 * @param addIds 后端形参名
 */
function layuiBaseTree($, tree, form, treeUrl, checkUrl, addUrl, elemTxt, paramId, addIds) {
    $.post(treeUrl, rs => {
        //渲染树
        tree.render(
            {
                id: elemTxt,
                elem: '#' + elemTxt,
                data: rs,
                showCheckbox: true,
            }
        )
        //返回id数组,设置节点勾选(使用场景:如根据用户id获取角色id的集合)
        $.post(checkUrl,
            {
                id: paramId
            },
            rs => {
                //id相同则选中节点,rs为id数组
                tree.setChecked(elemTxt, rs)
                //将勾选的节点进行提交(使用场景: 如给用户添加角色）
                //监听提交
                form.on('submit(submit)', data => {
                    //获取提交的字段
                    let field = data.field;
                    //勾选的id数组
                    let ids = []
                    $.each(field, (i, v) => {
                        //减0是为了返回number类型而不是string
                        ids.push(v - 0)
                    })
                    $.ajax(
                        {
                            type: 'post',
                            url: addUrl,
                            data: {id: paramId, [addIds]: ids.toString()},
                            success: rs => {
                                if (rs.ok) {
                                    parent.layui.table.reload('table'); //重载表格
                                    let index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
                                    parent.layer.close(index); //再执行关闭
                                } else {
                                    layer.msg(rs.msg)
                                }
                            }
                        }
                    )
                })
            })
    })
}

// *******************************************************layui自定义封装方法End************************************************************** //

/**
 * xmSelect--渲染下拉框
 *
 * @param $         jQuery对象
 * @param el        渲染对象
 * @param type      下拉框类型
 * @param url       请求的url
 * @param method    请求的方法
 * @param fun       回调函数，返回下拉框对象及数据
 * @param layVerify 是否开启表单验证
 * @param disabled  是否禁用
 * 下拉框数据格式：
 *  data: [
 *      {name: '张三', value: 1},
 *      {name: '李四', value: 2},
 *      {name: '王五', value: 3},
 *  ]
 */
function xmSelectRender($, el, type, url, method, fun, layVerify, disabled) {
    // 下拉框对象
    let obj;
    // 下拉框数据
    let data;
    // 配置项
    let option = {
        el: el,
        filterable: true,
        direction: 'up',
        toolbar: {show: true},
        data: []
    };
    if (layVerify) {
        option.layVerify = 'required';
    }
    if (disabled) {
        option.disabled = true;
    }
    switch (type) {
        // 单选框下拉框
        case -1:
            option.radio = true;
            option.clickClose = true;
            break;
        // 多选框下拉框
        case 0:
            break;
        // 单选框下拉树
        case 1:
            option.radio = true;
            option.clickClose = true;
            option.tree = {
                show: true,
                expandedKeys: true,
                strict: false
            };
            option.height = '400px';
            option.data = () => {
                $.ajax(
                    {
                        url: url,
                        type: method,
                        async: false,
                        success: rs => {
                            if (rs.success) {
                                data = rs.data;
                            }
                        }
                    }
                );
                return data;
            };
            // 渲染下拉框
            obj = xmSelect.render(option);
            fun ? fun(obj, data) : '';
            return;
        // 复选框下拉树
        case 2:
            option.tree = {
                show: true,
                expandedKeys: true
            };
            option.height = '400px';
            break;
        // 级联模式
        case 3:
            option.cascader = {
                show: true
            };
            break;
    }
    // 渲染下拉框
    obj = xmSelect.render(option);
    // 获取下拉框数据
    $.ajax(
        {
            url: url,
            type: method,
            async: false,
            success: rs => {
                if (rs.success) {
                    data = rs.data;
                    obj.update({
                        data: data,
                        autoRow: true,
                    });
                    fun ? fun(obj, data) : '';
                }
            }
        }
    );
}

